/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hextd.core;

import hextd.HexTD.Direction;
import hextd.hex.Hex;
import hextd.hex.HexBase;
import hextd.hex.HexEmpty;
import hextd.hex.HexPath;
import hextd.hex.HexTransparent;
import hextd.wave.Path;
import hextd.wave.PathNormal;
import java.util.List;
import java.util.ArrayList;

/**
 *
 * @author hylke
 */
public class GameGrid {

	private Context c;
	public Hex[][] grid = new Hex[2][2];
	private int gridWidth;
	private int gridHeight;
	public float minX, minY, maxX, maxY;
	private int lastPaddedLeft = -1;
	private boolean leftToRight = true;
	//
	private static final float wFloat = (float) Math.sin(Math.PI / 3);
	private List<String> source;

	public GameGrid(Context c) {
		this.c = c;
	}

	public void reScale() {
		minX = 0;
		minY = 0;
		maxX = (2f * wFloat * getGridWidth());
		maxY = (1.5f * ((float) getGridHeight() + 0.5f));
	}

	public Hex getHex(int col, int row) {
		if (col < grid.length && col >= 0 && grid[col] != null) {
			if (row >= 0 && row < grid[col].length) {
				return this.grid[col][row];
			}
		}
		return null;
	}

	public Hex getNeightbourOf(int col, int row, Hex.neighbours direction) {
		Hex neighbour = null;
		switch (direction) {
			case left:
				if (leftToRight) {
					neighbour = getHex(col - 1, row);
				} else {
					neighbour = getHex(col, row - 1);
				}
				break;
			case leftDown:
				if (leftToRight) {
					neighbour = getHex(col - ((row + 1) & 1), row + 1);
				} else {
					neighbour = getHex(col - 1, row - ((col + 1) & 1));
				}
				break;
			case leftUp:
				if (leftToRight) {
					neighbour = getHex(col - ((row + 1) & 1), row - 1);
				} else {
					neighbour = getHex(col + 1, row - ((col + 1) & 1));
				}
				break;
			case right:
				if (leftToRight) {
					neighbour = getHex(col + 1, row);
				} else {
					neighbour = getHex(col, row + 1);
				}
				break;
			case rightDown:
				if (leftToRight) {
					neighbour = getHex(col + (row & 1), row + 1);
				} else {
					neighbour = getHex(col - 1, row + (col & 1));
				}
				break;
			case rightUp:
				if (leftToRight) {
					neighbour = getHex(col + (row & 1), row - 1);
				} else {
					neighbour = getHex(col + 1, row + (col & 1));
				}
				break;
		}
		return neighbour;
	}

	public float[] getHexLocation(int col, int row) {
		float[] retval = {0, 0};
		if (leftToRight) {
			int shift = row & 1;
			retval[0] = wFloat + (col * 2 + shift) * wFloat;
			retval[1] = 1.5f * row + 1;
		} else {
			int shift = col & 1;
			retval[0] = 1.5f * col + 1;
			retval[1] = wFloat + (row * 2 + shift) * wFloat;
		}
		return retval;
	}

	public void resizeGrid(int width, int height, boolean top, boolean left) {
		int paddingLeft = 0;
		int paddingTop = 0;
		int cutLeft = 0;
		int cutTop = 0;
		int oddLeftPadding = 0;
		try {
			setGridWidth(width);
			setGridHeight(height);
		} catch (NumberFormatException e) {
		}

		Hex[][] newGrid = new Hex[getGridWidth()][getGridHeight()];
		if (left) {
			if (newGrid.length > grid.length) {
				paddingLeft = newGrid.length - grid.length;
			} else {
				cutLeft = grid.length - newGrid.length;
			}

		}

		if (top) {
			if (newGrid[0].length > grid[0].length) {
				paddingTop = newGrid[0].length - grid[0].length;
			} else {
				cutTop = grid[0].length - newGrid[0].length;
			}

		}

		if (top && (((paddingTop - cutTop) & 1) == 1)) {
			// padding left needed on odd rows
			oddLeftPadding = -lastPaddedLeft;
			lastPaddedLeft = oddLeftPadding;
		}

		for (int y = cutTop; y < grid[0].length; y++) {
			boolean odd = ((y & 1) == 1);
			if (oddLeftPadding < 0) {
				odd = !odd;
			}

			int xLength = grid.length - (y & 1);
			int thisPadLeft = odd ? oddLeftPadding : 0;
			if ((y < grid[0].length) &&
					(y >= 0) &&
					(y + paddingTop - cutTop < newGrid[0].length) &&
					(y + paddingTop - cutTop >= 0)) {
				for (int x = cutLeft - thisPadLeft; x <
						xLength; x++) {
					if (x < newGrid.length && x >= 0) {
						newGrid[x + paddingLeft - cutLeft + thisPadLeft][y + paddingTop - cutTop] = this.grid[x][y];
						newGrid[x + paddingLeft - cutLeft + thisPadLeft][y + paddingTop - cutTop].setLocation(x + paddingLeft - cutLeft + thisPadLeft, y + paddingTop - cutTop);
					}

				}
			}
		}

		for (int y = 0; y <
				newGrid[0].length; y++) {
			int xLength = newGrid.length - (y & 1);
			for (int x = 0; x <
					xLength; x++) {
				if (newGrid[x][y] == null) {
					newGrid[x][y] = new HexBase(x, y, c, true, leftToRight);
				}

			}
		}
		ArrayList<Path> paths = c.getPaths();
		for (int i = paths.size() - 1; i >= 0; i--) {
			PathNormal p = (PathNormal) paths.get(i);
			p.shift(Direction.SOUTH, paddingTop - cutTop, oddLeftPadding);
			p.shift(Direction.EAST, paddingLeft - cutLeft, oddLeftPadding);
		}

		grid = newGrid;
		pushGrid();
	}

	private void pushGrid() {
		if (source != null) {
			source.clear();
			String[] lines = new String[Math.max(grid[0].length, grid[1].length)];
			for (int i = 0; i < lines.length; i++) {
				lines[i] = "";
			}
			for (Hex[] col : grid) {
				int i = 0;
				for (Hex h : col) {
					if (h != null) {
						lines[i] += h.getShortName() + " ";
					}
					i++;
				}
			}
			for (String line : lines) {
				source.add(line.trim());
			}
		}
	}

	public void changeHex(Hex h, Hex.HexType to) {
		int col = h.getCol();
		int row = h.getRow();
		switch (to) {
			case base:
				grid[col][row] = new HexBase(col, row, c, true, leftToRight);
				break;

			case baseTransparent:
				grid[col][row] = new HexTransparent(col, row, c, leftToRight);
				break;

			case empty:
				grid[col][row] = new HexEmpty(col, row, c, leftToRight);
				break;

			case path:
				grid[col][row] = new HexPath(col, row, c, leftToRight);
				break;

		}
		grid[col][row].resetScale();
		pushGrid();
	}

	public void changeHex(int[] hex, char to) {
		int col = hex[0];
		int row = hex[1];
		if (row >= 0 && row < this.getGridHeight()) {
			if (col >= 0 && col < (this.getGridWidth() - (row & 1))) {
				this.grid[col][row].unSetTower();
				switch (to) {
					case 'b':
						this.grid[col][row] = new HexBase(col, row, c, true, leftToRight);
						break;

					case 'e':
					case 'p':
						this.grid[col][row] = new HexPath(col, row, c, leftToRight);
						break;

					case 'n':
						this.grid[col][row] = new HexEmpty(col, row, c, leftToRight);
						break;
				}
				pushGrid();
			}
		}
	}

	public int getGridWidth() {
		return gridWidth;
	}

	/**
	 * sets the width of this grid in hexes.
	 * @param gridWidth
	 */
	public void setGridWidth(int gridWidth) {
		this.gridWidth = gridWidth;
		reScale();
	}

	public int getGridHeight() {
		return gridHeight;
	}

	/**
	 * sets the height of this grid in hexes.
	 * @param gridHeight
	 */
	public void setGridHeight(int gridHeight) {
		this.gridHeight = gridHeight;
		reScale();
	}

	public void fillWith(List<String> gridData) {
		source = gridData;
		int height = gridData.size();
		String line = gridData.get(0);
		String[] splitData = line.split(" ");
		int width = splitData.length;
		if (leftToRight) {
			setGridHeight(height);
			setGridWidth(width);
			grid = new Hex[width][height];
		} else {
			setGridHeight(width);
			setGridWidth(height);
			grid = new Hex[height][width];
		}

		int colNr, rowNr;
		int lineNr = -1;
		for (String row : gridData) {
			lineNr++;
			int count = 0;
			for (int i = 0; i < row.length(); i++) {
				if (leftToRight) {
					colNr = count;
					rowNr = lineNr;
				} else {
					colNr = lineNr;
					rowNr = count;
				}
				char chr = row.charAt(i);
				if (chr != ' ') {
					if (colNr <= grid.length - (lineNr & 1)) {
						switch (chr) {
							case 'b':
								grid[colNr][rowNr] = new HexBase(colNr, rowNr, c, true, leftToRight);
								break;
							case 'e':
							case 'p':
								grid[colNr][rowNr] = new HexPath(colNr, rowNr, c, leftToRight);
								break;
							case 'n':
								grid[colNr][rowNr] = new HexEmpty(colNr, rowNr, c, leftToRight);
								break;
							case 't':
								grid[colNr][rowNr] = new HexTransparent(colNr, rowNr, c, leftToRight);
								break;
							default:
								System.err.println("GameGrid::fillWith: Unknown hex code: " + chr);
								break;
						}
					}
					count++;
				}
			}
		}
		for (Hex[] row : grid) {
			for (Hex h : row) {
				if (h != null) {
					h.initNeighbours();
				}
			}
		}
	}

	/**
	 * @return true if the hexes have sides on the left-right sides, false if
	 * they have hexes on the top-bottom sides.
	 */
	public boolean isLeftToRight() {
		return leftToRight;
	}

	/**
	 * @param true if the hexes have sides on the left-right sides, false if
	 * they have hexes on the top-bottom sides.
	 */
	public void setLeftToRight(boolean leftToRight) {
		this.leftToRight = leftToRight;
	}
}
